using System;
using System.Diagnostics;

using TrueCode.Core.Aspects;


namespace TrueCode.DependencyManager
{
  /// <summary>
  /// Represents the aim of the build session. Used to choose which <see cref="IBuildAction">build actions</see>
  /// is applicable during the session.
  /// Used by <see cref="IBuildAction">build actions</see> to determine what to do.
  /// </summary>
  [DebuggerDisplay( "{DebugString}", Name = "{Type}" )]
  [Serializable]
  public class SessionAim : IEquatable< SessionAim >
  {
    #region .ctors
    /// <param name="type">The type of the building object.</param>
    /// <param name="setting">Object represents the settings. Different build actions can be associated with the same
    /// aim type and different settings, see <see cref="Container.AddActionFor{TAim, TBuildAction}( object, TBuildAction )"/> 
    /// and <see cref="Container.Resolve{T}( object )"/> for details.</param>
    public SessionAim( [NotNull] Type type, [CanBeNull] object setting = null )
    {
      if( type == null ) throw new ArgumentNullException( "type" );

      Type = type;
      Setting = setting;
    }
    #endregion

    #region Properties
    [CanBeNull] public readonly object Setting;
    [NotNull] public readonly Type Type;
    #endregion

    #region Implementation of IEquatable<SessionAim>
    public bool Equals( SessionAim other )
    {
      return other != null && Type == other.Type && Equals( Setting, other.Setting );
    }
    #endregion

    #region Implementaion of equality
    public override bool Equals( object obj )
    {
      return Equals( obj as SessionAim );
    }

    public override int GetHashCode()
    {
      return Type.GetHashCode() ^ ( Setting == null ? 0 : Setting.GetHashCode() );
    }
    #endregion

    #region Debug information
    private string _debugString;

    private string DebugString
    {
      get
      {
        if( _debugString == null )
          _debugString = string.Format( "{0}, {1}", Type, Setting );
        return _debugString;
      }
    }

    public override string ToString()
    {
      return DebugString;
    }
    #endregion
  }

  [Serializable]
  public class SessionAim< T > : SessionAim
  {
    public SessionAim( [CanBeNull] object setting = null ) : base( typeof( T ), setting )
    {
    }
  }
}